require('dotenv').config()
const Koa = require('koa')
const Router = require('koa-router')
const bodyParser = require('koa-bodyparser')
const cors = require('koa-cors')
const serve = require('koa-static')
const path = require('path')
const fs = require('fs')
const { spawn } = require('child_process')
const CryptoJS = require('crypto-js')
const WebSocket = require('ws')
const log = require('log4node')

const app = new Koa()
const router = new Router()

// 确保temp目录存在
const tempDir = path.join(__dirname, 'temp')
if (!fs.existsSync(tempDir)) {
    fs.mkdirSync(tempDir, { recursive: true })
}

// 系统配置 - 从环境变量读取
const config = {
    // 请求地址
    hostUrl: process.env.TTS_HOST_URL || "wss://tts-api.xfyun.cn/v2/tts",
    host: process.env.TTS_HOST || "tts-api.xfyun.cn",
    // 在控制台-我的应用-在线语音合成（流式版）获取
    appid: process.env.XFYUN_APPID,
    // 在控制台-我的应用-在线语音合成（流式版）获取
    apiSecret: process.env.XFYUN_API_SECRET,
    // 在控制台-我的应用-在线语音合成（流式版）获取
    apiKey: process.env.XFYUN_API_KEY,
    uri: process.env.TTS_URI || "/v2/tts",
    deepseekApiKey: process.env.DEEPSEEK_API_KEY
}

// 验证必要的环境变量
if (!config.appid || !config.apiSecret || !config.apiKey) {
    console.error('错误: 请配置 .env 文件中的 XFYUN_APPID, XFYUN_API_SECRET, XFYUN_API_KEY')
    process.exit(1)
}

// 存储活跃的TTS请求
const activeRequests = new Map()

// 中间件
app.use(cors())
app.use(bodyParser())
app.use(serve(path.join(__dirname, 'public')))

// 鉴权签名
function getAuthStr(date) {
    let signatureOrigin = `host: ${config.host}\ndate: ${date}\nGET ${config.uri} HTTP/1.1`
    let signatureSha = CryptoJS.HmacSHA256(signatureOrigin, config.apiSecret)
    let signature = CryptoJS.enc.Base64.stringify(signatureSha)
    let authorizationOrigin = `api_key="${config.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`
    let authStr = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin))
    return authStr
}




// 将PCM转换为MP3
function convertPcmToMp3(pcmPath, mp3Path) {
    return new Promise((resolve, reject) => {
        const ffmpeg = spawn('ffmpeg', [
            '-f', process.env.AUDIO_FORMAT || 's16le',  // PCM格式
            '-ar', process.env.AUDIO_SAMPLE_RATE || '16000', // 采样率
            '-ac', process.env.AUDIO_CHANNELS || '1',     // 单声道
            '-i', pcmPath,  // 输入文件
            '-acodec', 'mp3', // 输出编码
            '-y',           // 覆盖输出文件
            mp3Path         // 输出文件
        ])

        ffmpeg.on('close', (code) => {
            if (code === 0) {
                resolve()
            } else {
                reject(new Error(`FFmpeg process exited with code ${code}`))
            }
        })

        ffmpeg.on('error', (err) => {
            reject(err)
        })
    })
}

// 音色配置
const voiceConfig = {
    // 女声
    'xiaoyan': { name: '小燕', gender: '女', description: '青年女声，甜美自然' },
    'vixq': { name: '小琪', gender: '女', description: '青年女声，温柔亲切' },
    'vixm': { name: '小美', gender: '女', description: '青年女声，活泼可爱' },
    'vixl': { name: '小丽', gender: '女', description: '青年女声，知性优雅' },
    'vixr': { name: '小柔', gender: '女', description: '青年女声，温柔细腻' },
    'vixying': { name: '小英', gender: '女', description: '青年女声，清新自然' },
    'vixyue': { name: '小悦', gender: '女', description: '青年女声，欢快活泼' },
    
    // 男声
    'xiaoyu': { name: '小宇', gender: '男', description: '青年男声，稳重成熟' },
    'vixf': { name: '小峰', gender: '男', description: '青年男声，磁性低沉' },
    'vixk': { name: '小凯', gender: '男', description: '青年男声，阳光活力' },
    'vixs': { name: '小帅', gender: '男', description: '青年男声，自信大方' },
    'vixx': { name: '小新', gender: '男', description: '青年男声，清新自然' },
    'vixy': { name: '小勇', gender: '男', description: '青年男声，坚定有力' },
    'vixz': { name: '小智', gender: '男', description: '青年男声，智慧沉稳' },
    
    // 默认音色
    'default': { name: '小燕', gender: '女', description: '默认女声' }
}

// TTS WebSocket处理函数
function createTTSWebSocket(text, requestId, voice = 'xiaoyan') {
    return new Promise((resolve, reject) => {
        const date = new Date().toUTCString()
        const wssUrl = config.hostUrl + "?authorization=" + getAuthStr(date) + "&date=" + date + "&host=" + config.host
        const ws = new WebSocket(wssUrl)
        
        const pcmPath = `./temp/temp_${requestId}.pcm`
        const mp3Path = `./temp/temp_${requestId}.mp3`
        
        // 存储请求信息
        activeRequests.set(requestId, {
            ws: ws,
            pcmPath: pcmPath,
            mp3Path: mp3Path,
            startTime: Date.now(),
            voice: voice
        })

        ws.on('open', () => {
            log.info(`WebSocket connected for request ${requestId}, voice: ${voice}`)
            
            // 发送TTS请求
            const frame = {
                "common": {
                    "app_id": config.appid
                },
                "business": {
                    "aue": "raw",
                    "auf": `audio/L16;rate=${process.env.AUDIO_SAMPLE_RATE || '16000'}`,
                    "vcn": voice, // 使用传入的音色参数
                    "tte": "UTF8"
                },
                "data": {
                    "text": Buffer.from(text).toString('base64'),
                    "status": 2
                }
            }
            log.info(`发送TTS请求: voice=${voice}, text=${text.substring(0, 20)}...`)
            ws.send(JSON.stringify(frame))
        })

        ws.on('message', (data) => {
            try {
                const res = JSON.parse(data)

                if (res.code != 0) {
                    log.error(`${res.code}: ${res.message}`)
                    ws.close()
                    reject(new Error(`TTS Error: ${res.message}`))
                    return
                }

                const audio = res.data.audio
                const audioBuf = Buffer.from(audio, 'base64')
                
                // 追加保存PCM数据
                fs.appendFileSync(pcmPath, audioBuf)

                if (res.code == 0 && res.data.status == 2) {
                    ws.close()
                    
                    // 转换PCM为MP3
                    convertPcmToMp3(pcmPath, mp3Path)
                        .then(() => {
                            // 清理PCM文件
                            fs.unlinkSync(pcmPath)
                            resolve(mp3Path)
                        })
                        .catch(err => {
                            log.error('MP3 conversion error: ' + err)
                            reject(err)
                        })
                }
            } catch (err) {
                log.error('Message parsing error: ' + err)
                reject(err)
            }
        })

        ws.on('close', () => {
            log.info(`WebSocket closed for request ${requestId}`)
            activeRequests.delete(requestId)
        })

        ws.on('error', (err) => {
            log.error(`WebSocket error for request ${requestId}: ` + err)
            activeRequests.delete(requestId)
            reject(err)
        })
    })
}



const OpenAI = require("openai");
require('dotenv').config()
const openai = new OpenAI({
        baseURL: 'https://api.deepseek.com',
        apiKey: process.env.DEEPSEEK_API_KEY
});



router.post('/api/deepseek/chat', async (ctx) => {
    try {
        const {message, conversationId} = ctx.request.body;
        
        if (!message) {
            ctx.status = 400;
            ctx.body = { error: '消息内容不能为空' };
            return;
        }
        
        const completion = await openai.chat.completions.create({
            messages: [{ role: "user", content: message }],
            model: "deepseek-chat",
        });
        
        ctx.body = {
            success: true,
            data: completion.choices[0].message.content
        };
        log.info(`deepseek 接口调用成功`);
        log.info(`deepseek 接口调用成功: ${completion.choices[0].message.content}`);
    } catch (error) {
        log.error('DeepSeek API 调用错误: ' + error.message);
        ctx.status = 500;
        ctx.body = { error: 'AI对话处理失败: ' + error.message };
    }
})
// 获取音色列表
router.get('/api/tts/voices', async (ctx) => {
    try {
        const voices = Object.entries(voiceConfig).map(([key, config]) => ({
            id: key,
            name: config.name,
            gender: config.gender,
            description: config.description
        }))
        
        ctx.body = {
            success: true,
            data: voices
        }
    } catch (error) {
        log.error('获取音色列表错误: ' + error.message)
        ctx.status = 500
        ctx.body = { error: '获取音色列表失败: ' + error.message }
    }
})

// 路由定义
router.post('/api/tts', async (ctx) => {
    try {
        const { text, voice = 'xiaoyan' } = ctx.request.body
        
        if (!text) {
            ctx.status = 400
            ctx.body = { error: '文本内容不能为空' }
            return
        }

        // 验证音色参数
        if (!voiceConfig[voice]) {
            ctx.status = 400
            ctx.body = { error: `不支持的音色: ${voice}` }
            return
        }

        const requestId = Date.now().toString()
        log.info(`开始处理TTS请求: ${requestId}, 文本: ${text}, 音色: ${voice}`)

        const mp3Path = await createTTSWebSocket(text, requestId, voice)
        
        // 读取MP3文件并返回
        const mp3Buffer = fs.readFileSync(mp3Path)
        
        // 设置响应头
        ctx.set('Content-Type', 'audio/mpeg')
        ctx.set('Content-Disposition', `attachment; filename="tts_${requestId}.mp3"`)
        ctx.set('Content-Length', mp3Buffer.length)
        
        ctx.body = mp3Buffer
        
        // 清理临时文件
        setTimeout(() => {
            if (fs.existsSync(mp3Path)) {
                fs.unlinkSync(mp3Path)
            }
        }, 5000) // 5秒后清理

    } catch (error) {
        log.error('TTS处理错误: ' + error.message)
        ctx.status = 500
        ctx.body = { error: 'TTS处理失败: ' + error.message }
    }
})

// 取消TTS请求
router.delete('/api/tts/:requestId', async (ctx) => {
    const { requestId } = ctx.params
    
    if (activeRequests.has(requestId)) {
        const request = activeRequests.get(requestId)
        
        // 关闭WebSocket连接
        if (request.ws.readyState === WebSocket.OPEN) {
            request.ws.close()
        }
        
        // 清理文件
        if (fs.existsSync(request.pcmPath)) {
            fs.unlinkSync(request.pcmPath)
        }
        if (fs.existsSync(request.mp3Path)) {
            fs.unlinkSync(request.mp3Path)
        }
        
        activeRequests.delete(requestId)
        
        ctx.body = { message: '请求已取消' }
    } else {
        ctx.status = 404
        ctx.body = { error: '请求不存在' }
    }
})

// 获取活跃请求列表
router.get('/api/tts/active', async (ctx) => {
    const activeList = Array.from(activeRequests.keys()).map(requestId => {
        const request = activeRequests.get(requestId)
        return {
            requestId,
            startTime: request.startTime,
            duration: Date.now() - request.startTime
        }
    })
    
    ctx.body = { activeRequests: activeList }
})

// 应用路由
app.use(router.routes())
app.use(router.allowedMethods())

// 启动服务器
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
    log.info(`TTS服务器启动在端口 ${PORT}`)
    log.info(`访问 http://localhost:${PORT} 查看前端页面`)
})

module.exports = app
